
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cmsis_os2.h"                          // CMSIS RTOS header file
 
/*----------------------------------------------------------------------------
 *      Thread 1 'Thread_Name': Sample thread
 
 不在Thread_Disp()驱动DAC，因为显示频率低。更新DAC需要和ADC同步（同频率）。
 *---------------------------------------------------------------------------*/
#include "dbgUart/dbgUart.h" 
#include "bsp.h"
#include "key.h"
#include "menu_seg.h"
#include "threads.h"
#include "parameter.h"
#include "preset_point.h"
#include "drv_ch423s.h"

#include "Thread_disp.h"


extern DTU_JSON dtu_json;

extern uint8_t in_sta;							//IN1状态：1---有效（valide），0---无效（invalid）。
extern uint8_t flag_type;
extern uint8_t flag_para_ok;
extern int32_t para_to_flash_2(uint32_t );
extern uint16_t CRC16(uint8_t *puchMsg, uint16_t usDataLen);



typedef enum {
STA_IDLE,
STA_UP, 
STA_DN
}DET_STA;

typedef struct _WT_DET{
	uint32_t ts_pre;
	uint32_t ts_cur;
	int32_t wt_up;
	int32_t wt_dn;
	int32_t wt_del;
	int32_t wt_hold;	//监测点的称重值，用于计算保持显示时长。
	uint32_t ts_hold;	//监测点的时间戳，用于计算保持显示时长。
	uint32_t cnt_10ms;	//因为线程continue原因，超时不准确。
	uint8_t to_mode;	//是否要求切换显示模式（disp_mode)
	uint8_t to_send;	//是否要发送数据到4G模块。
	DET_STA sta;		//上次的状态：STA_UP, STA_DN.
}WT_DET;


PRESET_P preset_point[5];	//[0]不使用，使用[1~4]。

static int32_t norm_in1_deal(MSG_U msg, int32_t wt);
static void seg_pwr_on_disp(void);
static void do_ser_cal(MSG_U* msg);

static int32_t prepoint_satisfy(uint32_t n, int32_t val);
static void prepoint_sta(uint32_t n, int32_t val);

static void spoint_config(void);

int32_t get_str_wt(char* str, int32_t wt);
int32_t get_str_ts(char* str);	
int32_t get_str_gps(char* str);

int32_t offset_manual;			//手动触发				在显示模式下，按下zero键；显示值在清零范围。			-1*显示值 --> offset
int32_t	offset_pwr_on;			//上电自动清零			上电；上电清零开关有效；显示值在清零范围。				-1*显示值 --> offset_pwr_on
int32_t	offset_zero_trace;		//零点跟踪				显示值在跟踪范围；持续时间超过1.6秒。					-1*显示值 --> offset_zero_range


uint8_t flag_NOT_in_menu_mode;	//是否在MENU_MODE，是为1，不是为0。在MENU_MODE时，不实时处理OUT1，OUT2。
typedef enum{
	DISP_NORM, 
	DISP_ERR, 
	DISP_MENU, 
	DISP_ANA, 
	DISP_HOLD,
	DISP_HOLD_WT
}DISP_MODE;				//0-based. 数码管的显示模式（简称显示模式，区别于单个seg的显示模式：SEG_MODE）。

DISP_MODE disp_mode= DISP_NORM;

WT_DET wt_det={.sta= STA_IDLE, .ts_pre= -1};


/*菜单项目
*/ 
void Thread_Disp (void *argument);                   // thread function
 

int Init_Thread_Disp (void) {
	osThreadId_t tid_Thread;                        // thread id
	
	const osThreadAttr_t attr={.stack_size= 2048};                       // thread id 
	tid_Thread = osThreadNew(Thread_Disp, NULL, &attr);
	if (tid_Thread == NULL) {
		return(-1);
	}
 
	return(0);
}


//extern int32_t offset_disp;		//显示时的偏移量。



__NO_RETURN void Thread_Disp (void *argument) {
	(void)argument;	//Prevent unused argument(s) compilation warning.
	
	char str[48];
	char str_ts[20];	//含'\0'的个数。
	char str_wt[20];		//含'\0'的个数和可能的1小数点，例："12.3"，最长"12345.6"。
	char str_gps[256];	//含'\0'的个数。
	
	int32_t wt;
	osStatus_t ret;
	uint16_t key;				//从消息队列中获取的按键值。
	MSG_U msg;					//组合消息

	
	spoint_config();
	
	menu_init();
	//
	//bsp_seg_hal();			//使用CH423S，不再直接驱动数码管。
	while(0 == flag_para_ok){
		osDelay(100);
	}
	
	uartS("\nThread_disp(N) start...\n");
	
	
	seg_pwr_on_disp();			//上电启动界面。
	
	BLE_ON;						//!!开启BLE芯片供电，造成3.3V瞬间跌落，可能引起MCU进入HardFault。
	//BLE_OFF;
	
	disp_mode= DISP_NORM;
	flag_NOT_in_menu_mode= 1;
	
	
	while (1) {
		//接收按键消息。
		ret= osMessageQueueGet(mid_key_disp_io, &msg, 0, 10);
		
		if(osOK != ret){
			//无消息时的超时处理。!!不能去掉。
			continue;			
		}
		
		
		if(MSG_TYPE_MV_WT == msg.type){
			wt= msg.wt;							//更新称重值，以便后用。
			
			if(dbg_sw & DBG_THREAD_DISP)			
				uartS("msg_mv_wt");
			
			//预置点参与称重处理（未放在ADC ISR，因考虑不需要实时）。
			prepoint_sta(1, msg.wt);
			prepoint_sta(2, msg.wt);
			prepoint_sta(3, msg.wt);
			prepoint_sta(4, msg.wt);
		}
		else{
			if(dbg_sw & DBG_THREAD_DISP)
				uartS("msg_key");		//线程Thread_In()定时发送In1状态，In1也按msg_key处理。
		}
		
		
		/*串口标定处理：不管处于什么显示状态。
		!!标定过程需要uV，AD值，只有在本线程才能得到。
		*/
		if(0< op_ser_cal.op_sta){
			uartS("\n do_ser_cal");
			do_ser_cal(&msg);
		}
		
		
		
		
		if(DISP_NORM == disp_mode){			//称重模式（正常显示模式）
			
			/*查看io def中IN1的选择，若非“无定义”，则需要处理：
			QQ仅仅在DISP_NORM中执行，对吗？
			*/
			if(MSG_TYPE_KEY == msg.type){
				//处理IN1的消息
				norm_in1_deal(msg, wt);			//wt是上一次称重消息中的重量，非实时称重值。!!目前只在DISP_NORM下进行检测。
				
				//显示模式是否切换。
				if(wt_det.to_mode){
					wt_det.wt_hold= wt;			//wt是保存之前的称重值。
					wt_det.cnt_10ms= 0;	
					
					wt_det.to_mode= 0;			//切换标志清零。
					disp_mode= DISP_HOLD_WT;	//
					
					uartS("\nDISP_NORM -> DISP_HOLD_WT");
					continue;
				}
			}
			
			
			/*更新显示。
			*/
			if(MSG_TYPE_MV_WT == msg.type){
				//显示重量值
				if(flag_to_zero){
					flag_to_zero= 0;
					para_xxx.zero= 0;
					
					offset_manual+= -1*msg.wt;	//QQ!!在这儿还是在ISR中更新offset_manual好？
					
					uartS("\nzero disp");
				}
				
				seg_wt_to_seg(msg.wt, msg.dat[0]);	//msg.dat[0]为指示灯位段或。
				wt= msg.wt;							//更新称重值，以便后用。
				
				if(dbg_sw & DBG_THREAD_DISP){
					sprintf(str, "\n%d:raw= %d, ad= %d, wt= %d,uv=%d,st=%02x",TIM2->CNT, msg.raw, msg.ad, msg.wt, msg.uv, msg.dat[0]);
					uartS(str);
						
					sprintf(str, "\no_manu= %d, o_pwr=%d, o_auto=%d",offset_manual, offset_pwr_on, offset_zero_trace);
					uartS(str);
				}
			}
			else if(MSG_TYPE_KEY == msg.type){
				/*称重模式下的顶层菜单按键处理：
				K1_ESC:		
				K2_OPT:		
				K3_MOD:
				K4_ENTER:
				*/
				key= msg.key;
				
				if(KEY_K3_MODE == key){
					//获取第1个菜单项，并显示。
					cur_item= get_first_item();
					if(cur_item->f_enter != NULL)
						cur_item->f_enter(msg);
					
					seg_updata(cur_item->content);
					disp_mode= DISP_MENU;
					
					uartS("\nenter menu");
				}
				else if(KEY_K1_ESC == key){
					//清零。
					if(0 == para_xxx.range_zero){
						seg_updata("Error2");
						osDelay(500);
					}
					else{
						flag_to_zero= 1;
						uartS("\n key to zero");
					}
				}				
				else if(KEY_K2_OPT == key){
					//HOLD模式触发。
					if(0 !=strcmp(ITEM_DIG_0, _tbl_dig_0_4[para_xxx.hold_mode_idx])){
						disp_mode= DISP_HOLD;
						
						uartS("\nDISP_NORM-->DISP_HOLD");
					}
				}
				else if(KEY_K2_OPT_L == key){
					//同DT45：长按OPT键3秒，进入模拟量显示。
					disp_mode= DISP_ANA;
					seg_set_norm_to_ana();
					
					uartS("\nDISP_NORM-->DISP_ANA");
				}
				else if(KEY_K4_ENTER == key){
					if(0 == strcmp(ITEM_IN_6, _tbl_in[para_xxx.in1_define_idx])){	//切换保持功能下的触发状态。
						hold_trig_sta= !hold_trig_sta;	
						
						sprintf(str, "\nL%d,hold_trig_sta= %d", __LINE__, hold_trig_sta);
						uartS(str);
					}
				}
				else{}
			}	
		}
		else if(DISP_HOLD_WT == disp_mode){		//称重值保持一定时长。
			
			seg_wt_to_seg(wt_det.wt_hold, LED_HOLD_BIT);		//保持显示，HOLD灯亮）
			
			if(wt_det.to_send){
				wt_det.to_send= 0;
				
				uartS("\n send data to 4G module\n\n\n");
				
				
				/*填充dtu_json。格式如下：属性键值对间用逗号分开。分组用{}包含（分组符号前后不能有额外空格。
				{"DateTime":"2023-11-03 11:20:36","Datas":[{"Type":"tension","UnitType":"n","Value":"300"},{"Type":"weigh","UnitType":"kg","Value":"30"}],\
				"Gps":[{"Type":"longitude","Value":"128.1234567"},{"Type":"latitude","Value":"37.1234567"},{"Type":"height","UnitType":"m","Value":"23"}]}
				*/
				get_str_ts(str_ts);
				get_str_wt(str_wt, (wt_det.wt_up- wt_det.wt_dn));
				get_str_gps(str_gps);
				
				//使用了占位符：前4个0，为EF，长度和类型占位。后2个CC为CRC16占位。
				dtu_json.len=\
				sprintf(dtu_json.dtu_str, "0000{\"DateTime\":\"%s\",\"Datas\":[{\"Type\":\"Weigh\",\"UnitType\":\"kg\",\"Value\":\"%s\"}], %s}CC", str_ts, str_wt, str_gps);
				
				dtu_json.dtu_str[0]=0xEF;	//239
				dtu_json.dtu_str[1]=(dtu_json.len-6);		//数据段长度，已测，需LSB first.
				dtu_json.dtu_str[2]=(dtu_json.len-6)>>8;	
				dtu_json.dtu_str[3]=0x01;	//类型
				
				uint16_t crc16= CRC16((uint8_t*)dtu_json.dtu_str, dtu_json.len-2);
				dtu_json.dtu_str[dtu_json.len-2]= crc16;
				dtu_json.dtu_str[dtu_json.len-2]= crc16>> 8;
				
				uartS(&dtu_json.dtu_str[4]);	//当dtu_json.dtu_str[2]为0时，调试信息不全。
				
				osEventFlagsSet(evt_id_dtu, 0x00000001U);			//待ISR完成后，再做可能的调度。
			}
			
			
			
			/*2种退出称重保持显示的方法：
			a. 超时，自动退回到DISP_NORM。
			b. ESC键，退回到DISP_NORM。
			*/
			uint32_t ts=ts_get();
			uint32_t del= ts_del_o_n(wt_det.ts_hold, ts);
			
			if(del>= (_tbl_int_disp_hold_time[para_self.disp_hold_time_idx]*1000)){
				disp_mode= DISP_NORM;
				
				uartS("\ntmo:DISP_HOLD_WT -> DISP_NORM");
				
			}
			
			if((MSG_TYPE_KEY == msg.type) && (KEY_K1_ESC == msg.key)){	//支持ESC键
				disp_mode= DISP_NORM;
				
				uartS("\nesc:DISP_HOLD_WT -> DISP_NORM");
			}
		}
		else if(DISP_HOLD == disp_mode){
			//动态刷新para_xxx.triger_hold_hi和para_xxx.triger_hold_lo。
			//wt= u16_to_int32(para_xxx.triger_hold_hi, para_xxx.triger_hold_lo);
			wt= hold_val_max_min_del_sample;
			
		
			osKernelLock();
			para_xxx.triger_hold_hi= ((uint32_t)wt)>> 16;	//更新HOLD保持值，需锁定保护，以免只更新16bit，而非32bit。
			para_xxx.triger_hold_lo= (uint32_t)wt;
			osKernelUnlock();
			
			seg_wt_to_seg(wt, LED_HOLD_BIT);		//msg.dat[0]固定为0：Hold灯亮（稳定信号，归零信号等）。
			
			
			//同时处理按键。
			if(MSG_TYPE_KEY == msg.type){
				/*仅K2_OPT有效:		
				*/
				key= msg.key;
				
				if(KEY_K2_OPT == key){
					disp_mode= DISP_NORM;

					uartS("\nDISP_HOLD-->DISP_NORM");
				}
				else if(KEY_K4_ENTER == key){
					if(0 == strcmp(ITEM_IN_6, _tbl_in[para_xxx.in1_define_idx])){	//切换保持功能下的触发状态。
						hold_trig_sta= !hold_trig_sta;	
						
						sprintf(str, "\nL%d,hold_trig_sta= %d", __LINE__, hold_trig_sta);
						uartS(str);
					}
				}
			}
		}
		else if(DISP_ANA == disp_mode){		//模拟量显示模式（和DISP_NORM一样，只是显示值不同而已）
			/*显示模拟输出：按当前的模拟输出方式显示，如当前模拟输出方式为0~20mA，则显示xx.yyy(单位是mA)。若输出方式为0~5V，则显示x.yyy(单位V）。
			按显示的更新速度（1刷新/50ms），
			短按ZERO清零，短按OPT退回DISP_NORM。
			*/
			//uartS("A");
			
			/*查看io def中IN1的选择，若非“无定义”，则需要处理：
			*/
			if(MSG_TYPE_KEY == msg.type){
				//处理IN1的消息
				norm_in1_deal(msg, wt);
			}
			
			/*更新显示。
			*/
			if(MSG_TYPE_MV_WT == msg.type){
				//手动清零@模拟量显示。
				if(flag_to_zero){
					flag_to_zero= 0;
					para_xxx.zero= 0;
					
					offset_manual+= -1*msg.wt;	//QQ!!在这儿还是在ISR中更新offset_manual好？
					
					uartS("\nzero disp");
				}
				
				seg_wt_to_seg_in_ana(msg.wt, msg.dat[0]);	//msg.dat[0]有稳定信号，归零信号等。
				
				if(dbg_sw & DBG_THREAD_DISP){
					sprintf(str, "\nANA:%d:ad= %d, wt= %d,uv=%d,st=%02x",TIM2->CNT, msg.ad, msg.wt, msg.uv, msg.dat[0]);
					uartS(str);
						
					sprintf(str, "\no_manu= %d, o_pwr=%d, o_auto=%d",offset_manual, offset_pwr_on, offset_zero_trace);
					uartS(str);
				}
			}
			else if(MSG_TYPE_KEY == msg.type){
				/*模拟量显示下的按键处理：
				K1_ESC:		
				K2_OPT:		
				*/
				key= msg.key;
				
				if(KEY_K1_ESC == key){
					//清零。
					flag_to_zero= 1;
					uartS("\n key to zero in DISP_ANA");
				}				
				else if(KEY_K2_OPT == key){
					disp_mode= DISP_NORM;
					seg_set_ana_to_norm();
					
					//flag_to_zero= 1;
					uartS("\nDISP_ANA --> DISP_NORM");
				}
				else{}
			}			
		}
		else if(DISP_MENU == disp_mode){	//菜单模式
			
			flag_NOT_in_menu_mode= 0;
			
			if(MSG_TYPE_KEY == msg.type){
				key= msg.key;
				
				if((NULL == cur_item->parent) && (KEY_K1_ESC == key)){	//cur_item指向setup...cal，有ESC按键，则退出DISP_MENU。只有setup...菜单项的parent是NULL，即它们是顶层菜单。
					disp_mode= DISP_NORM;
					mode_mv_wt= MODE_WT;		//Thread_ADC()发送称重值（非uV值）。
					
					flag_NOT_in_menu_mode= 1;
					
					uartS("\nMENU to NORM");
				}
				else{
					if(cur_item->f_key != NULL)
						cur_item->f_key(msg);	//!!每个菜单项有自己的按键处理函数，主要是菜单项指针的更改。
					else{
						uartS("\n$err:no f_key");
					}
				}
			}
			else{
				//菜单项处理非按键消息（称重消息，mv消息等）。
				if(cur_item->f_key != NULL)
					cur_item->f_key(msg);		//!!每个菜单项有自己的按键处理函数，可能还要处理非按键消息（例，称重值...）。
			}
		}
		else if(DISP_ERR == disp_mode){		//错误显示模式（准备作废）
			//错误显示模式
		}
	}
}



/*正常显示模式下，对in1消息的处理函数。
参数 msg：
参数 wt: 当前称重值（是上1个称重消息中的称重值）。
依据para_xxx.in1_define进行处理：
para_xxx.in1_define		处理方法
	1					对显示清零
	2					对限制1的状态清零
	3					对限制2的状态清零
	4					对限制3的状态清零
	5					对限制4的状态清零
	6					触发保持
	7					电平保持
*/
static int32_t norm_in1_deal(MSG_U msg, int32_t wt)
{
	uint16_t key;
	char str[32];
	
	key= msg.key;
	
	
	if(MSG_TYPE_KEY != msg.type)
		return 0;
	
	
	if(0 == strcmp(ITEM_IN_0, _tbl_in[para_xxx.in1_define_idx])){
		//无定义，即不使用in1。
	}
	else if(0 == strcmp(ITEM_IN_1, _tbl_in[para_xxx.in1_define_idx])){
		//对显示清零
		if(KEY_IN1_TO_VALID == key)
			flag_to_zero= 1;
	}
	else if(0 == strcmp(ITEM_IN_2, _tbl_in[para_xxx.in1_define_idx])){
	
	}
	else if(0 == strcmp(ITEM_IN_3, _tbl_in[para_xxx.in1_define_idx])){
	
	}
	else if(0 == strcmp(ITEM_IN_4, _tbl_in[para_xxx.in1_define_idx])){
	
	}
	else if(0 == strcmp(ITEM_IN_5, _tbl_in[para_xxx.in1_define_idx])){
	
	}
	else if(0 == strcmp(ITEM_IN_6, _tbl_in[para_xxx.in1_define_idx])){
		if(KEY_IN1_TO_VALID == key){	//切换保持功能下的触发状态。
			hold_trig_sta= !hold_trig_sta;	
			
			sprintf(str, "\nhold_trig_sta= %d", hold_trig_sta);
			uartS(str);
		}
	}
	else if(0 == strcmp(ITEM_IN_7, _tbl_in[para_xxx.in1_define_idx])){
	
	}
	else if(0 == strcmp(ITEM_IN_8, _tbl_in[para_xxx.in1_define_idx])){	//垃圾车应用
		/*几种测试场景：
		a. 将铁物贴近接近开关，上电。快速移开铁物后再贴近。这时会忽略这个检测，因为.ts_pre=0，时间间隔太小。
		b. 再显示保持时，贴近接近开关。显示保持状态，不处理接近开关消息。
		c. 
		*/
		if(KEY_IN1_TO_VALID == key){
			uint32_t ts= ts_get();
			uint32_t ts_delta= ts_del_o_n(wt_det.ts_pre, ts);
			
			if(ts_delta< (_tbl_int_interval_min[para_self.up_dn_interval_min_idx]*1000)){
				//间隔太小，忽略本次检测点。
				sprintf(str, "\nommit this IN1's valid:%d", ts);
				uartS(str);
				
				//!!不更新wt_det.ts_pre。
			}
			else{
				if(ts_delta> _tbl_int_interval_max[para_self.up_dn_interval_max_idx]*1000){
					//间隔太大，认为是第一次称重。
					wt_det.sta= STA_UP;
					
					wt_det.wt_up= wt;
					wt_det.ts_hold= ts;
					wt_det.ts_pre= ts;
					
					
					wt_det.to_mode= 1;
					
					sprintf(str, "\n\nwt_up:%d", ts);
					uartS(str);
				}
				else{
					if(STA_UP == wt_det.sta){
					//间隔符合，认为是第二次称重。
						wt_det.sta= STA_DN;
						
						wt_det.wt_dn= wt;
						wt_det.ts_hold= ts;
						wt_det.ts_pre= ts;
						
						
						wt_det.to_mode= 1;
						wt_det.to_send= 1;
						
						sprintf(str, "\n\nwt_dn:%d", ts);
						uartS(str);
					}
					else{
						//上一次是下降，则本次认为是上升。
						wt_det.sta= STA_UP;
					
						wt_det.wt_up= wt;
						wt_det.ts_hold= ts;
						wt_det.ts_pre= ts;
						
						
						wt_det.to_mode= 1;
						
						sprintf(str, "\nwt_up:%d", ts);
						uartS(str);
					}
				}
			}
		}
	}
	else
		uartS("\n unkown in1_define");
	
	return 0;
}



///*【准备作废】根据输入（显示值，IN1状体），更改预置点状态。
//返回值：0
//输入参数 wt: 待显示的称重值
//*/
//static int32_t preset_point_deal(int32_t wt)
//{
//	if(( para_xxx.out1_define< 3 ) && (para_xxx.out2_define< 3)){
//		//不使用限制1~4，则直接退出。
//		return 0;
//	}
//	
//	
//	//处理OUT1
//	if(0 == strcmp(ITEM_DIG_03, _tbl_out[para_xxx.out1_define_idx])){
//		//使用限制1	
//	}
//	else if(0 == strcmp(ITEM_DIG_04, _tbl_out[para_xxx.out1_define_idx])){
//		//使用限制2
//	}
//	else if(0 == strcmp(ITEM_DIG_05, _tbl_out[para_xxx.out1_define_idx])){
//		//使用限制3
//	}
//	else if(0 == strcmp(ITEM_DIG_06, _tbl_out[para_xxx.out1_define_idx])){
//		//使用限制4
//	}
//	else
//		uartS("\nunkown out1_define");
//	
//	
//	//处理OUT2
//	if(0 == strcmp(ITEM_DIG_03, _tbl_out[para_xxx.out2_define_idx])){
//		//使用限制1
//		if(preset_point[1].flag_wait_unsatisfy){
//		
//		}
//			
//	}
//	else if(0 == strcmp(ITEM_DIG_04, _tbl_out[para_xxx.out2_define_idx])){
//		//使用限制2
//	}
//	else if(0 == strcmp(ITEM_DIG_05, _tbl_out[para_xxx.out2_define_idx])){
//		//使用限制3
//	}
//	else if(0 == strcmp(ITEM_DIG_06, _tbl_out[para_xxx.out2_define_idx])){
//		//使用限制4
//	}	
//	else
//		uartS("\nunkown out2_define");
//	
//	return 0;

//}



/*将wt输入后，看是否满足指定预置点的条件。
返回值：0---满足，其他---不满足
输入参数 wt: 称重值（待显示的）
输入参数 idx: 预置点序号，有效范围[1,4]。
!!暂不支持外部触发。
*/
static int32_t preset_point_satisfy(int32_t wt, int32_t idx)
{
	if((0 == para_xxx.preset_p1_condition) && (1 == idx)) 
		return -1;	//禁止（当前不满足）
	
	if((0 == para_xxx.preset_p2_condition) && (2 == idx)) 
		return -1;	//禁止（当前不满足）
	
	if((0 == para_xxx.preset_p3_condition) && (3 == idx)) 
		return -1;	//禁止（当前不满足）
	
	if((0 == para_xxx.preset_p4_condition) && (4 == idx)) 
		return -1;	//禁止（当前不满足）
	
	if(1 == idx){
		if(1 == para_xxx.preset_p1_condition){
			//< 
		}
		else if(2 == para_xxx.preset_p1_condition){
			//<= 
		}
		else if(3 == para_xxx.preset_p1_condition){
			//== 
		}
		else if(4 == para_xxx.preset_p1_condition){
			//>= 
		}
		else if(5 == para_xxx.preset_p1_condition){
			//> 
		}
		else if(6 == para_xxx.preset_p1_condition){
			//!= 
		}
		else if(7 == para_xxx.preset_p1_condition){
			//区间外
		}
		else if(8 == para_xxx.preset_p1_condition){
			//区间内（含区间值）
		}
	}
	
	return 0;
}



/*上电显示秒闪2次"8.8.8.8.8.8."，再显示"0ForcE"1秒。
*/
static void seg_pwr_on_disp(void)
{
	osStatus_t ret;
	uint16_t key;				//从消息队列中获取的按键值。
	MSG_U msg;					//组合消息
	uint32_t cnt= 0;
	uint32_t cp;
	int32_t icp;
	uint32_t ts,ts_2;
	char str[32];
	
//	cp= para_xxx.fs_max_hi;
//	cp<<= 16;
//	cp|= para_xxx.fs_max_lo;
//	
//	icp= (int32_t)cp;	//最大量程
	
	
	dbg_sw|= DBG_BUZ;	
	buz_beep(100);
	
//	for(int i= 0; i< 3; i++){
//		
//		seg_disp_8_dot();
//		osDelay(250);
//		
//		seg_disp_blank();
//		osDelay(250);
//	}
//	
//	buz_beep(100);
//	seg_disp_logo();
//	osDelay(1000);
	
	dbg_sw&= ~DBG_BUZ;
	
	
	
	//上电自动清零
	if(0 == strcmp(ITEM_OFF, _tbl_off_on[para_xxx.zero_auto_sw_idx])){
		uartS("\n zero_auto NO");
		return;
	}
	
	ts= ts_get();
	while(1){
		ret= osMessageQueueGet(mid_key_disp_io, &msg, 0, 10);
		
		if(osOK != ret){
			continue;			
		}
		
		if(MSG_TYPE_MV_WT != msg.type){
			continue;
		}	
		
		
		if(dbg_sw & DBG_THREAD_DISP)			
			uartS("\nmsg_mv_wt_pwr_on");
		
		if(msg.dat[0] & LED_STAB){
			if(msg.wt<= (fs_max*para_xxx.range_zero/100))
				cnt++;
			else
				cnt= 0;
		} 
		else
			cnt= 0;

		
		/*N秒超时，暂定为2秒。
		*/
		ts_2= ts_get();
		sprintf(str, "\nwt= %d, n=%d, dat0=%02x",msg.wt, cnt, msg.dat[0]);
		uartS(str);

		
		if(2000< ts_del_o_n(ts, ts_2)){
			if(16<= cnt){	//在2000ms内，应可以收到40个显示消息，这里暂定30满足即可。
				offset_pwr_on+= -1*msg.wt;	//使用当前显示值
				
				uartS("\n zero@pwr on");
				buz_beep(200);
			}
			
			sprintf(str,"\n zero_auto err, cnt=%d< 16", cnt); 
			uartS(str);
			break;	//跳出循环
		}
		else
			uartS("*");
	}
	
	dbg_sw&= ~DBG_BUZ;	//注释掉，有按键音。
}




/*执行串口标定。
若传入的消息不是MV_MT，什么也不做，等下次。
*/
static void do_ser_cal(MSG_U* msg)
{
	char str[48];
	
	
	if(MSG_TYPE_MV_WT == msg->type){
		if(stab_arr.mv_stab){
			//有数据，且显示稳定，则保持该值。
			switch (op_ser_cal.op_sta){
				case 1:	//标定零点
					point[0].used= 1;
					point[0].ad= msg->ad;
					point[0].uv= msg->uv;
					point[0].load= 0;
					
//					point[1].used= 0;
//					point[2].used= 0;
//					point[3].used= 0;
//					point[4].used= 0;
					break;
				
				case 2:	//标定第1个砝码
					point[1].used= 1;
					point[1].ad= msg->ad;
					point[1].uv= msg->uv;
					point[1].load= op_ser_cal.op_in;
				
					break;
				
				case 3:	//标定第2个砝码
					point[2].used= 1;
					point[2].ad= msg->ad;
					point[2].uv= msg->uv;
					point[2].load= op_ser_cal.op_in;
				
					break;
				
				case 4:	//标定第3个砝码
					point[3].used= 1;
					point[3].ad= msg->ad;
					point[3].uv= msg->uv;
					point[3].load= op_ser_cal.op_in;
				
					break;
				
				case 5:	//标定第4个砝码
				default:
					point[4].used= 1;
					point[4].ad= msg->ad;
					point[4].uv= msg->uv;
					point[4].load= op_ser_cal.op_in;
				
					break;
			}
			
			
			//
			sprintf(str, "\ndo_ser_cal:point[%d], uv=%d, load=%d, ad=%d", op_ser_cal.op_sta-1, point[op_ser_cal.op_sta-1].uv, point[op_ser_cal.op_sta-1].load,point[op_ser_cal.op_sta-1].ad); 
			uartS(str);
			
			//写入FLASH。
			if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
				uartS("\nok:save ser_cal's point[]");
			
				op_ser_cal.op_sta= 0;
				op_ser_cal.op_ret= 0;
			}
			else{
				uartS("\nerr:save ser_cal's point[]");
				op_ser_cal.op_sta= -1;	//写FLASH失败
				op_ser_cal.op_ret= 4;
			}
		}
		else{
			//不稳定，则不执行标定，即标定失败。
			op_ser_cal.op_sta= -2;		//不稳定
			op_ser_cal.op_ret= 2;		//不稳定
			
			uartS("\ndo ser cal: NOT STAB");
		}
	}
	else{}
}



/*限制点n（1~4）是否满足条件。
返回值：0 ---满足，其他 ---不满足。
输入参数 n: 限制点序号（1~4）
输入参数 val: 待比较的值，即称重值。
!!当判断条件（即PX.3有效条件）为9或10时，须使用上一次满足情况。
*/
static int32_t prepoint_satisfy(uint32_t n, int32_t val)
{
	//static int32_t ret_pre= -1;			//上次状态（0--满足，其他--不满足）
	int32_t val1=0,val2=0;				//用于有符号比较。
	int32_t val_min, val_max;			//用于有符号比较。	
	int32_t val_set, val_thred;			//设定值和阈值
	
	uint32_t tmp32;
	uint16_t cond;
	
	
	if(1 == n){
		tmp32= para_xxx.preset_p1_val_1_hi;
		tmp32<<= 16;
		tmp32|= para_xxx.preset_p1_val_1_lo;
		val1= (int32_t)tmp32;
		
		tmp32= para_xxx.preset_p1_val_2_hi;
		tmp32<<= 16;
		tmp32|= para_xxx.preset_p1_val_2_lo;
		val2= (int32_t)tmp32;
		
		cond= para_xxx.preset_p1_condition;		
	}
	else if(2 == n){
		tmp32= para_xxx.preset_p2_val_1_hi;
		tmp32<<= 16;
		tmp32|= para_xxx.preset_p2_val_1_lo;
		val1= (int32_t)tmp32;
		
		tmp32= para_xxx.preset_p2_val_2_hi;
		tmp32<<= 16;
		tmp32|= para_xxx.preset_p2_val_2_lo;
		val2= (int32_t)tmp32;
		
		cond= para_xxx.preset_p2_condition;
	}
	else if(3 == n){
		tmp32= para_xxx.preset_p3_val_1_hi;
		tmp32<<= 16;
		tmp32|= para_xxx.preset_p3_val_1_lo;
		val1= (int32_t)tmp32;
		
		tmp32= para_xxx.preset_p3_val_2_hi;
		tmp32<<= 16;
		tmp32|= para_xxx.preset_p3_val_2_lo;
		val2= (int32_t)tmp32;
		
		cond= para_xxx.preset_p3_condition;
	}
	else if(4 == n){
		tmp32= para_xxx.preset_p4_val_1_hi;
		tmp32<<= 16;
		tmp32|= para_xxx.preset_p4_val_1_lo;
		val1= (int32_t)tmp32;
		
		tmp32= para_xxx.preset_p4_val_2_hi;
		tmp32<<= 16;
		tmp32|= para_xxx.preset_p4_val_2_lo;
		val2= (int32_t)tmp32;
		
		cond= para_xxx.preset_p4_condition;
	}
	else{
		cond= 0;	
	}
	
	
	if(0 == cond)
			return -1;	//条件是禁止，直接返回-1（即不满足）。
	
	val_min= val1>val2 ? val2:val1;	//取小者。
	val_max= val1>val2 ? val1:val2;	//取大者。
	
	val_set= val1;
	val_thred= val2;
	
	if(1 == cond){
		//<
		if(val< val_min)
			return 0;	//满足，返回0。
		else
			return -1;	//不满足
	}
	else if(2 == cond){
		//<=
		if(val<= val_min)
			return 0;
		else
			return -1;	//不满足
	}
	else if(3 == cond){
		//==
		if(val == val_min)
			return 0;
		else
			return -1;	//不满足
	}	
	else if(4 == cond){
		//>=
		if(val >= val_min)
			return 0;
		else
			return -1;	//不满足
	}
	else if(5 == cond){
		//>
		if(val > val_min)
			return 0;
		else
			return -1;	//不满足
	}
	else if(6 == cond){
		//!=
		if(val != val_min)
			return 0;
		else
			return -1;	//不满足
	}
	else if(7 == cond){
		//__<>__区间外
		if((val < val_min) || (val> val_max))
			return 0;
		else
			return -1;	//不满足
	}
	else if(8 == cond){
		//=<__>=区间内
		if((val_min<= val) || (val<= val_max))
			return 0;
		else
			return -1;	//不满足
	}
	else if(9 == cond){
		//外部触发：暂未实现，直接返回-1。
		//高限值比较
		if(val>= val_set){
			return 0;	//满足
		}
		else if(val< (val_set-val_thred)){
			return -1;
		}
		else{
			//在[val_set-val_thrd, val_set)时。
			if(preset_point[n].sta_cur){
				return 0;	//上次满足，则本次也满足。
			}
			else 
				return -1;	//上次不满足，本次也不满足。
		}
	}
	else if(10 == cond){
		//低限值比较
		if(val<= val_set){
			return 0;	//满足
		}
		else if(val> (val_set+val_thred)){
			return -1;
		}
		else{
			//在(val_set,val_set+val_thrd]时，若上次满足，则本次满足。
			if(preset_point[n].sta_cur){	
				return 0;	//上次满足，则本次也满足。
			}
			else 
				return -1;	//上次不满足，本次也不满足。
		}
	}
	else
		return -1;		//不满足
}






/*预置点n（1~4）的状态。
输入参数 n: 限制点序号，以指定限制点
输入参数 val: 称重值
说明：上次状态，本次状态，都是瞬时状态。
      sta_out输出状态是对瞬时状态处理后的状态，不会瞬时变化。
      sta_fin最终状态是由IN1参与，和“开关量测试开关”参与后的状态。
先更新预置点状态，再进行开关量输出（开关量输出和预置点状态是简单关系）。
*/
static void prepoint_sta(uint32_t n, int32_t val)
{
	uint16_t stab_need=0;		//是否判稳
	uint16_t duration_min=0;	//最小持续时间
	uint16_t cond;				//有效条件
	char str[32];
	
	/*限制点的某些变量，不方便用n索引，搞成变量就摆脱n依赖。
	*/
	if(1 == n){
		stab_need= para_xxx.preset_p1_need_stab;
		duration_min= para_xxx.preset_p1_duration_min;
		cond= para_xxx.preset_p1_condition;
	}
	else if(2 == n){
		stab_need= para_xxx.preset_p2_need_stab;
		duration_min= para_xxx.preset_p2_duration_min;
		cond= para_xxx.preset_p2_condition;
	}
	else if(3 == n){
		stab_need= para_xxx.preset_p3_need_stab;
		duration_min= para_xxx.preset_p3_duration_min;
		cond= para_xxx.preset_p3_condition;
	}
	else if(4 == n){
		stab_need= para_xxx.preset_p4_need_stab;
		duration_min= para_xxx.preset_p4_duration_min;
		cond= para_xxx.preset_p4_condition;
	}
	
	
	/*
	有效条件是高、低限值(9,10)时，不需要稳定时间。
	*/
	if((9 == cond) || (10 == cond))	
		stab_need= 0;
	
	
	/*是否满足条件
	*/
	if(0 == prepoint_satisfy(n, val)){
		if((dbg_sw & DBG_PRESET_POINT) && (1==n)){
			sprintf(str, "\n\tsatisfy %d",n);
			uartS(str);
		}
		
		//满足指定条件（返回0），本次状态有效。
		preset_point[n].sta_cur= 1;	
		
		if(preset_point[n].flag_wait_unsatisfy){	//是否等待“变为无效”。只有等待无效，才能向下判断。
			uartS("\ngoto IN_DEAL");
			goto IN_DEAL;	//跳转到IN对限制值的清零处理。
		}
		
		if(0 == preset_point[n].sta_pre){
			//上次条件状态为无效，本次为有效，则为一个转变，需要记录时间。
			preset_point[n].ts_valid_start= osKernelGetTickCount();
			preset_point[n].ts_valid_start_valid= 1;
			
			preset_point[n].stab_cnt= 0;
			
			if(dbg_sw & DBG_PRESET_POINT){
				sprintf(str, "\n\tinvalid->valid:%d",n);
				uartS(str);
			}
		}
		else{
			//上次有效，本次有效，没有变化。若起始时间戳无效（即已处理过转换期，现在为平稳期），则不处理。
			if(0 == preset_point[n].ts_valid_start_valid)
				goto IN_DEAL;
		}
		
		
		if(stab_need){	
			if(stab_arr.wt_stab){
				//AD值判稳定，是由AD处理函数决定的，这里仅使用。
				preset_point[n].stab_cnt++;
				
				if(10< preset_point[n].stab_cnt){
					preset_point[n].stab_cnt= 11;	//不再自增
					
					if((dbg_sw & DBG_PRESET_POINT) && (1== n)){
						sprintf(str, "\n\tsatisfy's sta_cnt ok:%d", n);
						uartS(str);
					}
				}
			}
			
			//需要条件判稳。
			if(duration_min*100< (osKernelGetTickCount()- preset_point[n].ts_valid_start)){	//ms值判断。QQ暂未考虑Tick溢出，因为按ms算，32-bit溢出，需要>49d。
//				if(10< preset_point[n].stab_cnt){
//					preset_point[n].sta_out= 1;		//输出状态（既要满足持续时间，又要满足稳定次数）。
//					
//					if(dbg_sw & DBG_PRESET_POINT){
//						sprintf(str, "\n\t\t\tsta_out=1(stab):%d", n);
//						uartS(str);
//					}
//				}
				
				preset_point[n].sta_out= 1;		//输出状态（既要满足持续时间，又要满足稳定次数）。

				preset_point[n].ts_valid_start_valid= 0;	//标示为已处理，处于平稳期。
				
				if(dbg_sw & DBG_PRESET_POINT){
					sprintf(str, "\n\t\t\tsta_out=1(stab):%d", n);
					uartS(str);
				}
			}
		}
		else{
			preset_point[n].sta_out= 1;	//直接的状态
			
			if(dbg_sw & DBG_PRESET_POINT){
				sprintf(str, "\n\t\tsta_out=1(dire):%d", n);
				uartS(str);
			}
		}
	}
	else{
		if((dbg_sw & DBG_PRESET_POINT)&& (1==n)){
			sprintf(str, "\nUnsatisfy %d",n);
			uartS(str);
		}
		
		preset_point[n].sta_cur= 0;//不满足指定条件，本次状态无效。
		
		if(1 == preset_point[n].sta_pre){
			//由有效变无效。
			preset_point[n].ts_invalid_start= osKernelGetTickCount();
			preset_point[n].ts_invalid_start_valid= 1;
			
			preset_point[n].stab_cnt= 0;
			
			if(dbg_sw & DBG_PRESET_POINT){
				sprintf(str, "\n\tvalid->invalid:%d", n);
				uartS(str);
			}
		}
		else{
			//上次无效，本次无效，没有变化。若起始时间戳无效（即已处理过转换期，现在为平稳期），则不处理。
			if(0 == preset_point[n].ts_invalid_start_valid)
				goto DO_UNSATISFY;
		}
		
		
		if(stab_need){
			if(stab_arr.wt_stab){
				preset_point[n].stab_cnt++;
				
				if(10< preset_point[n].stab_cnt){
					preset_point[n].stab_cnt= 11;	//不再自增
				
					if((dbg_sw & DBG_PRESET_POINT) && (1== n)){
						sprintf(str, "\n\tunsatisfy's sta_cnt ok:%d", n);
						uartS(str);
					}					
				}
			}
			
			//需要判稳。
			if(duration_min*100< (osKernelGetTickCount()- preset_point[n].ts_invalid_start)){	//ms值判断。QQ暂未考虑Tick wrap
				
//				if(10< preset_point[n].stab_cnt){
//					preset_point[n].sta_out= 0;	//输出状态
//					
//					if(dbg_sw & DBG_PRESET_POINT){
//						sprintf(str, "\n\t\t\tsta_out=0(stab):%d", n);
//						uartS(str);
//					}
//				}
				
				preset_point[n].sta_out= 0;	//输出状态
				preset_point[n].ts_invalid_start_valid= 0;		//标示为已处理，处于平稳期。
				
				if(dbg_sw & DBG_PRESET_POINT){
					sprintf(str, "\n\t\t\tsta_out=0(stab):%d", n);
					uartS(str);
				}				
			}
		}
		else{
			preset_point[n].sta_out= 0;	//直接的状态
			
			if(dbg_sw & DBG_PRESET_POINT){
				sprintf(str, "\n\t\tsta_out=0(dire):%d", n);
				uartS(str);
			}
		}
		
		
DO_UNSATISFY:	
		if(preset_point[n].flag_wait_unsatisfy){
			if(0 == preset_point[n].sta_out){
				preset_point[n].flag_wait_unsatisfy= 0;	//已检测到状态无效，所以清零等待无效标志。
				
				if(dbg_sw & DBG_PRESET_POINT){
					uartS("\n\t\t\t\t0 -->flag_wait_unsatify");
				}
			}
		}
	}
	

IN_DEAL:	
	preset_point[n].sta_pre= preset_point[n].sta_cur;	//!!每次比较后，都要更新上次状态。
	
	
	if((9 == cond) || (10 == cond)){	
		/*
		有效条件是高、低限值(9,10)时，不受IN1影响，直接说出当前值。
		*/
		preset_point[n].sta_fin= preset_point[n].sta_out;
	}
	else{
		/*再结合上IN有效时，对限制点状态的影响。
		IN1定义为清零限制1~4，且IN1有效。!!IN1只用于一个限制点。当IN1有效时，直接将相应限制点置为无效，设定相应限制点为“等待条件不满足”。		
		*/
		if((1< para_xxx.in1_define_idx)&&(para_xxx.in1_define_idx< 6)){
			if(in_sta){
				if((2 == para_xxx.in1_define_idx) && (1 == n)){			//IN1定义为：清零限制点1。		
					preset_point[n].sta_fin= 0;
					preset_point[n].flag_wait_unsatisfy= 1;
					if(dbg_sw & DBG_PRESET_POINT){
						uartS("\nIN1 valid");
					}
				}
				else if((3 == para_xxx.in1_define_idx) && (2 == n)){	//IN1定义为：清零限制点2。
					preset_point[n].sta_fin= 0;
					preset_point[n].flag_wait_unsatisfy= 1;
				}
				else if((4 == para_xxx.in1_define_idx) && (3 == n)){	//IN1定义为：清零限制点3。
					preset_point[n].sta_fin= 0;
					preset_point[n].flag_wait_unsatisfy= 1;
				}
				else if((5 == para_xxx.in1_define_idx) && (4 == n)){	//IN1定义为：清零限制点4。
					preset_point[n].sta_fin= 0;
					preset_point[n].flag_wait_unsatisfy= 1;
				}
			}
			else{
				//IN1无效（即不清零，不参与），那么可以用.sta_out更新.sta_fin。
				if(0 == preset_point[n].flag_wait_unsatisfy){
					//不在等待“条件无效”，直接赋值
					preset_point[n].sta_fin= preset_point[n].sta_out;
				}
				else{
					//正在等待“条件无效”，值不变。
					preset_point[n].sta_fin= preset_point[n].sta_fin;	//.sta_fin不变。
				}
			}
		}
		else{	
			//IN1不参与。
			preset_point[n].sta_fin= preset_point[n].sta_out;	
		}
	}
	
	
	/*再结合“开关量测试开关”，才能进一步更新OUT1，OUT2引脚。否则，不更新OUT1，OUT2。
	*/
	if(para_coil & COIL_BIT_MASK_RST_SW){
		//do nothing.
		uartS("\n sw test io");
	}
	else{
		if(dbg_sw & DBG_PRESET_POINT){
			sprintf(str, "\nsta_fin=%d:%d",preset_point[n].sta_fin, n);
			uartS(str);
		}
		//先更新寄存器状态
		if(1 == n){ 
			if(preset_point[n].sta_fin)
				para_01_05.preset_1_sta= 1;
			else
				para_01_05.preset_1_sta= 0;
		}
		else if(2 == n){ 
			if(preset_point[n].sta_fin)
				para_01_05.preset_2_sta= 1;
			else
				para_01_05.preset_2_sta= 0;
		}
		else if(3 == n){ 
			if(preset_point[n].sta_fin)
				para_01_05.preset_3_sta= 1;
			else
				para_01_05.preset_3_sta= 0;
		}
		else if(4 == n){ 
			if(preset_point[n].sta_fin)
				para_01_05.preset_4_sta= 1;
			else
				para_01_05.preset_4_sta= 0;
		}
		
		/*再更新可能的引脚状态（用preset_point[n].used_n不好）。
		只有在out1_define，out2_define中引用了限制点，才能正真的作用到OUT1，OUT2引脚，否则，只更改限制点状态。
		*/
		if((2+ n) == para_xxx.out1_define_idx){
//			if(dbg_sw & DBG_PRESET_POINT){
//				uartS("\n out1_define");
//			}
			//OUT1定义和限制n关联
			if(0 == (para_coil & COIL_BIT_MASK_TEST_SW)){	//不在test io。
				if(preset_point[n].sta_fin)
					OUT1_VALID;
				else
					OUT1_INVALID;
			}
		}
		
		if((2+ n) == para_xxx.out2_define_idx){
//			if(dbg_sw & DBG_PRESET_POINT){
//				uartS("\n out2_define");
//			}
			if(preset_point[n].sta_fin)
				OUT2_VALID;
			else
				OUT2_INVALID;
		}		
	}
}



///*预置点n（1~4）的状态。
//输入参数 n: 限制点序号，以指定限制点
//输入参数 val: 称重值
//说明：上次状态，本次状态，都是瞬时状态。
//      sta_out输出状态是对瞬时状态处理后的状态，不会瞬时变化。
//      sta_fin最终状态是由IN1参与，和“开关量测试开关”参与后的状态。
//先更新预置点状态，再进行开关量输出（开关量输出和预置点状态是简单关系）。
//*/
//static void prepoint_sta(uint32_t n, int32_t val)
//{
//	uint16_t stab_need=0;		//是否判稳
//	uint16_t duration_min=0;	//最小持续时间
//	char str[32];
//	
//	/*限制点的某些变量，不方便用n索引，搞成变量就摆脱n依赖。
//	*/
//	if(1 == n){
//		stab_need= para_xxx.preset_p1_need_stab;
//		duration_min= para_xxx.preset_p1_duration_min;
//	}
//	else if(2 == n){
//		stab_need= para_xxx.preset_p2_need_stab;
//		duration_min= para_xxx.preset_p2_duration_min;
//	}
//	else if(3 == n){
//		stab_need= para_xxx.preset_p3_need_stab;
//		duration_min= para_xxx.preset_p3_duration_min;
//	}
//	else if(4 == n){
//		stab_need= para_xxx.preset_p4_need_stab;
//		duration_min= para_xxx.preset_p4_duration_min;
//	}
//	
//	
//	/*是否满足条件
//	*/
//	if(0 == prepoint_satisfy(n, val)){
//		if((dbg_sw & DBG_PRESET_POINT) && (1==n)){
//			sprintf(str, "\n\tsatisfy %d",n);
//			uartS(str);
//		}
//		
//		//满足指定条件（返回0），本次状态有效。
//		preset_point[n].sta_cur= 1;	
//		
//		if(preset_point[n].flag_wait_unsatisfy){	//是否等待“变为无效”。只有等待无效，才能向下判断。
//			uartS("\ngoto IN_DEAL");
//			goto IN_DEAL;	//跳转到IN对限制值的清零处理。
//		}
//		
//		if(0 == preset_point[n].sta_pre){
//			//上次条件状态为无效，本次为有效，则为一个转变，需要记录时间。
//			preset_point[n].ts_valid_start= osKernelGetTickCount();
//			preset_point[n].stab_cnt= 0;
//			
//			if(dbg_sw & DBG_PRESET_POINT){
//				sprintf(str, "\n\tinvalid->valid:%d",n);
//				uartS(str);
//			}
//		}
//		
//			
//		if(stab_need){	
//			if(stab_arr.wt_stab){
//				//AD值判稳定，是由AD处理函数决定的，这里仅使用。
//				preset_point[n].stab_cnt++;
//				
//				if(10< preset_point[n].stab_cnt){
//					preset_point[n].stab_cnt= 11;	//不再自增
//					
//					if((dbg_sw & DBG_PRESET_POINT) && (1== n)){
//						sprintf(str, "\n\tsatisfy's sta_cnt ok:%d", n);
//						uartS(str);
//					}
//				}
//			}
//			
//			//需要条件判稳。
//			if(duration_min*100< (osKernelGetTickCount()- preset_point[n].ts_valid_start)){	//ms值判断。QQ暂未考虑Tick溢出，因为按ms算，32-bit溢出，需要>49d。
//				if(10< preset_point[n].stab_cnt){
//					preset_point[n].sta_out= 1;	//输出状态（既要满足持续时间，又要满足稳定次数）。
//					
//					if(dbg_sw & DBG_PRESET_POINT){
//						sprintf(str, "\n\t\t\tsta_out=1(stab):%d", n);
//						uartS(str);
//					}
//				}
//			}
//		}
//		else{
//			preset_point[n].sta_out= 1;	//直接的状态
//			
//			if(dbg_sw & DBG_PRESET_POINT){
//				sprintf(str, "\n\t\tsta_out=1(dire):%d", n);
//				uartS(str);
//			}
//		}
//	}
//	else{
//		if((dbg_sw & DBG_PRESET_POINT)&& (1==n)){
//			sprintf(str, "\nUnsatisfy %d",n);
//			uartS(str);
//		}
//		
//		preset_point[n].sta_cur= 0;//不满足指定条件，本次状态无效。
//		
//		if(1 == preset_point[n].sta_pre){
//			//由有效变无效。
//			preset_point[n].ts_invalid_start= osKernelGetTickCount();
//			preset_point[n].stab_cnt= 0;
//			
//			if(dbg_sw & DBG_PRESET_POINT){
//				sprintf(str, "\n\tvalid->invalid:%d", n);
//				uartS(str);
//			}
//		}
//		
//		if(stab_need){
//			if(stab_arr.wt_stab){
//				preset_point[n].stab_cnt++;
//				
//				if(10< preset_point[n].stab_cnt){
//					preset_point[n].stab_cnt= 11;	//不再自增
//				
//					if((dbg_sw & DBG_PRESET_POINT) && (1== n)){
//						sprintf(str, "\n\tunsatisfy's sta_cnt ok:%d", n);
//						uartS(str);
//					}					
//				}
//			}
//			
//			//需要判稳。
//			if(duration_min*100< (osKernelGetTickCount()- preset_point[n].ts_invalid_start)){	//ms值判断。QQ暂未考虑Tick
//				
//				if(10< preset_point[n].stab_cnt){
//					preset_point[n].sta_out= 0;	//输出状态
//					
//					if(dbg_sw & DBG_PRESET_POINT){
//						sprintf(str, "\n\t\t\tsta_out=0(stab):%d", n);
//						uartS(str);
//					}
//				}					
//			}
//		}
//		else{
//			preset_point[n].sta_out= 0;	//直接的状态
//			
//			if(dbg_sw & DBG_PRESET_POINT){
//				sprintf(str, "\n\t\tsta_out=0(dire):%d", n);
//				uartS(str);
//			}
//		}
//		
//		
//		if(preset_point[n].flag_wait_unsatisfy){
//			if(0 == preset_point[n].sta_out){
//				preset_point[n].flag_wait_unsatisfy= 0;	//已检测到状态无效，所以清零等待无效标志。
//				
//				uartS("\n\t\t\t\t0 -->flag_wait_unsatify");
//			}
//		}
//	}
//	

//IN_DEAL:	
//	preset_point[n].sta_pre= preset_point[n].sta_cur;
//	
//	/*再结合上IN有效时，对限制点状态的影响。
//	IN1定义为清零限制1~4，且IN1有效。		
//	*/
//	if((1< para_xxx.in1_define)&&(para_xxx.in1_define< 6)){
//		if(in_sta){
//			if((2 == para_xxx.in1_define) && (1 == n)){			//IN1定义为：清零限制点1。		
//				preset_point[n].sta_fin= 0;
//				preset_point[n].flag_wait_unsatisfy= 1;
//				uartS("\nIN1 valid");
//			}
//			else if((3 == para_xxx.in1_define) && (2 == n)){	//IN1定义为：清零限制点2。
//				preset_point[n].sta_fin= 0;
//				preset_point[n].flag_wait_unsatisfy= 1;
//			}
//			else if((4 == para_xxx.in1_define) && (3 == n)){	//IN1定义为：清零限制点3。
//				preset_point[n].sta_fin= 0;
//				preset_point[n].flag_wait_unsatisfy= 1;
//			}
//			else if((5 == para_xxx.in1_define) && (4 == n)){	//IN1定义为：清零限制点4。
//				preset_point[n].sta_fin= 0;
//				preset_point[n].flag_wait_unsatisfy= 1;
//			}
//		}
//		else{
//			//IN1无效，不参与。
//			if(0 == preset_point[n].flag_wait_unsatisfy)
//				preset_point[n].sta_fin= preset_point[n].sta_out;
//		}
//	}
//	else{	
//		//IN1不参与。
//		preset_point[n].sta_fin= preset_point[n].sta_out;	
//	}
//	
//	
//	/*再结合“开关量测试开关”，才能进一步更新OUT1，OUT2引脚。否则，不更新OUT1，OUT2。
//	*/
//	if(para_coil & COIL_BIT_MASK_RST_SW){
//		//do nothing.
//		uartS("\n sw test io");
//	}
//	else{
//		if(dbg_sw & DBG_PRESET_POINT){
//			sprintf(str, "\nsta_fin=%d:%d",preset_point[n].sta_fin, n);
//			uartS(str);
//		}
//		//先更新寄存器状态
//		if(1 == n){ 
//			if(preset_point[n].sta_fin)
//				para_01_05.preset_1_sta= 1;
//			else
//				para_01_05.preset_1_sta= 0;
//		}
//		else if(2 == n){ 
//			if(preset_point[n].sta_fin)
//				para_01_05.preset_2_sta= 1;
//			else
//				para_01_05.preset_2_sta= 0;
//		}
//		else if(3 == n){ 
//			if(preset_point[n].sta_fin)
//				para_01_05.preset_3_sta= 1;
//			else
//				para_01_05.preset_3_sta= 0;
//		}
//		else if(4 == n){ 
//			if(preset_point[n].sta_fin)
//				para_01_05.preset_4_sta= 1;
//			else
//				para_01_05.preset_4_sta= 0;
//		}
//		
//		/*再更新可能的引脚状态（用preset_point[n].used_n不好）。
//		只有在out1_define，out2_define中引用了限制点，才能正真的作用到OUT1，OUT2引脚，否则，只更改限制点状态。
//		*/
//		if((2+ n) == para_xxx.out1_define){
////			if(dbg_sw & DBG_PRESET_POINT){
////				uartS("\n out1_define");
////			}
//			//OUT1定义和限制n关联
//			if(preset_point[n].sta_fin)
//				OUT1_VALID;
//			else
//				OUT1_INVALID;
//		}
//		
//		if((2+ n) == para_xxx.out2_define){
////			if(dbg_sw & DBG_PRESET_POINT){
////				uartS("\n out2_define");
////			}
//			if(preset_point[n].sta_fin)
//				OUT2_VALID;
//			else
//				OUT2_INVALID;
//		}		
//	}
//}

static void spoint_config(void)
{		
	preset_point[1].sta_pre= 0;					//不满足
	preset_point[1].sta_cur= 0;					//不满足
	preset_point[1].flag_wait_unsatisfy= 0;		//不是”等待变为不满足”。
	preset_point[1].ts_valid_start_valid= 0;	//时间戳无效
	preset_point[1].ts_invalid_start_valid= 0;	//时间戳无效

	preset_point[2].sta_pre= 0;
	preset_point[2].sta_cur= 0;
	preset_point[2].flag_wait_unsatisfy= 0;
	preset_point[2].ts_valid_start_valid= 0;
	preset_point[2].ts_invalid_start_valid= 0;

	preset_point[3].sta_pre= 0;
	preset_point[3].sta_cur= 0;
	preset_point[3].flag_wait_unsatisfy= 0;
	preset_point[3].ts_valid_start_valid= 0;
	preset_point[3].ts_invalid_start_valid= 0;

	preset_point[4].sta_pre= 0;
	preset_point[4].sta_cur= 0;
	preset_point[4].flag_wait_unsatisfy= 0;
	preset_point[4].ts_valid_start_valid= 0;
	preset_point[4].ts_invalid_start_valid= 0;
}	




/************************ END OF FILE ************************/
